package com.googlecode.archimedes.filegen.model;

import java.util.HashSet;
import java.util.Set;

/**
 * This represents the BusinessObject Entity for GenerateableTemplates
 * 
 * @author John Lema, Erik Gustavson
 * @version $Id: Entity.java 3078 2006-10-03 16:42:22 +0000 (Tue, 03 Oct 2006) erik $
 * @since Archimedes 1.0
 */
public class Entity extends AbstractType implements Abstractable {

    public Entity                extendedEntity      = null;
    public Set<Interface>        interfaces          = new HashSet<Interface>();
    public Set<String>           interfaceRefs       = new HashSet<String>();
    private boolean              abstractClass       = false;
    private Boolean              auditable           = null;
    private Boolean              evaluatable         = null;

    private static final boolean AUDITABLE_DEFAULT   = false; //EG 10-03-2006
    private static final boolean EVALUATABLE_DEFAULT = false;

    /**
     * Returns true if there are any interfaces in the interface set
     * @return
     */
    public boolean hasInterfaces() {
        return !getInterfaces().isEmpty();
    }

    /** 
     * @see com.tps.filegen.model.AbstractType#getMembers(boolean)
     */
    @Override
    public Set<Member> getMembers(boolean includeInherited) {
        return addInterfaceMembers(super.getMembers(includeInherited));
    }

    /** 
     * @see com.tps.filegen.model.AbstractType#getRelationships(boolean)
     */
    @Override
    public Set<Relationship> getRelationships(boolean includeInherited) {
        return addInterfaceRelationships(super.getRelationships(includeInherited));
    }

    /**
     * Adds in the interface members to the passed in set of members
     * @param raw
     * @return
     */
    protected Set<Member> addInterfaceMembers(Set<Member> raw) {
        for (Interface anInterface : getInterfaces()) {
            raw.addAll(anInterface.getMembers());
        }

        return raw;
    }

    /**
     * Adds in the interface relations to the passed in set of relations
     * @param raw
     * @return
     */
    protected Set<Relationship> addInterfaceRelationships(Set<Relationship> raw) {
        for (Interface anInterface : getInterfaces()) {
            raw.addAll(anInterface.getRelationships());
        }

        return raw;
    }

    /** 
     * @see com.tps.filegen.model.AbstractType#getExtendedType()
     */
    @Override
    protected AbstractType getExtendedType() {
        return getExtendedEntity();
    }

    public boolean isExtendingEntity() {
        return getExtendsReference() != null;
    }

    /**
     * Returns the extendedEntity.
     *
     * @return Entity value of extendedEntity
     */
    public Entity getExtendedEntity() {
        return extendedEntity;
    }

    /**
     * Sets the extendedEntity
     * @param extendedEntity The extendedEntity to set.
     */
    public void setExtendedEntity(Entity extendedEntity) {
        this.extendedEntity = extendedEntity;
    }

    /**
     * Returns the interfaceRefs.
     *
     * @return Set<String> value of interfaceRefs
     */
    public Set<String> getInterfaceRefs() {
        return interfaceRefs;
    }

    /**
     * Sets the interfaceRefs
     * @param interfaceRefs The interfaceRefs to set.
     */
    public void setInterfaceRefs(Set<String> interfaceRefs) {
        this.interfaceRefs = interfaceRefs;
    }

    /**
     * Returns the interfaces.
     *
     * @return Set<Interface> value of interfaces
     */
    public Set<Interface> getInterfaces() {
        return interfaces;
    }

    /**
     * Sets the interfaces
     * @param interfaces The interfaces to set.
     */
    public void setInterfaces(Set<Interface> interfaces) {
        this.interfaces = interfaces;
    }

    /**
     * Add an interface to this entity
     * @param anInterface
     */
    public void addInterface(Interface anInterface) {
        this.getInterfaces().add(anInterface);
    }

    /**
     * Adds an interface reference
     * @param interfaceRef
     */
    public void addInterfaceRef(String interfaceRef) {
        this.getInterfaceRefs().add(interfaceRef);
    }

    /**
     * Returns the abstractClass.
     *
     * @return boolean value of abstractClass
     */
    public boolean isAbstract() {
        return abstractClass;
    }

    /**
     * Sets the abstractClass
     * @param abstractClass The abstractClass to set.
     */
    public void setAbstract(boolean abstractClass) {
        this.abstractClass = abstractClass;
    }

    /**
     * Returns the auditable.
     * 
     * First check if we are auditable. If we have
     * a null value, check our parent class (if one exists) and use
     * their auditable value. Finally, if our parent does not
     * have the setting, use the default value.
     *
     * @return boolean value of auditable
     */
    public boolean isAuditable() {

        if (auditable != null) {
            return auditable.booleanValue();
        } else if (isExtendingEntity()) { return getExtendedEntity().isAuditable(); }

        return AUDITABLE_DEFAULT;
    }

    /**
     * Sets the auditable
     * @param auditable The auditable to set.
     */
    public void setAuditable(boolean auditable) {
        this.auditable = auditable;
    }

    /**
     * Returns the evaluatable.
     *
     * First check if we are evaluatable. If we have
     * a null value, check our parent class (if one exists) and use
     * their evaluatable value. Finally, if our parent does not
     * have the setting, use the default value.
     * 
     * @return boolean value of evaluatable
     */
    public boolean isEvaluatable() {
        if (evaluatable != null) {
            return evaluatable.booleanValue();
        } else if (isExtendingEntity()) { return getExtendedEntity().isEvaluatable(); }

        return EVALUATABLE_DEFAULT;
    }

    /**
     * Sets the evaluatable
     * @param evaluatable The evaluatable to set.
     */
    public void setEvaluatable(boolean evaluatable) {
        this.evaluatable = evaluatable;
    }
}